﻿namespace SsisLdapSource.DirectoryServicesProtocolsExtensions
{
    using System;
    using System.Collections.Generic;
    using System.DirectoryServices.Protocols;
    using System.Linq;

    public class PagedSearchRequest : System.DirectoryServices.Protocols.SearchRequest
    {
        public PagedSearchRequest(ILdapSearchRequestPropertiesContainer ildapSearchRequestPropertiesContainer)
        {
            if (ildapSearchRequestPropertiesContainer.PageSize < 1)
            {
                throw new ArgumentNullException("ildapSearchRequestPropertiesContainer", "PageResultRequestControl requies a non 0 value for PageSize");
            }
           
            if (string.IsNullOrEmpty(ildapSearchRequestPropertiesContainer.SearchBaseDN))
            {
                throw new ArgumentNullException("ildapSearchRequestPropertiesContainer", "Search Base DN must not be null");
            }

            if (ildapSearchRequestPropertiesContainer.IncludeObjectOwnerInfo)
            {
                var securityDescriptorFlagControl =
                    new SecurityDescriptorFlagControl(SecurityMasks.Owner);
                Controls.Add(securityDescriptorFlagControl);
            }

            // Is adding this control is required by AD (confirm this)
            // This control is not supported by EDirectory
            // Consider intorodusing flag isActiveDirectory
            if (ildapSearchRequestPropertiesContainer.IsDomainScopeEnforced)
            {
                var searchOptionsControlDomainScope =
                new SearchOptionsControl(SearchOption.DomainScope);
                Controls.Add(searchOptionsControlDomainScope);
            }
            
            var pageResultRequestControl = 
                new PageResultRequestControl(ildapSearchRequestPropertiesContainer.PageSize);
            Controls.Add(pageResultRequestControl);

            DistinguishedName = ildapSearchRequestPropertiesContainer.SearchBaseDN;
            Filter = ildapSearchRequestPropertiesContainer.SearchFilter;
            Scope = SearchScope.Subtree;
            Attributes.AddRange(ildapSearchRequestPropertiesContainer.AttributesToLoad);  
        }

        public IEnumerable<SearchResultEntryCollection> Execute(LdapConnection ldapConnection)
        {
            if (!Controls.OfType<PageResultRequestControl>().Any())
            {
                throw new Exception("Paged Search requests require PageResultRequestControl to be included in the search request object");
            } 

            while (true)
            {
                var searchResponse = (SearchResponse)ldapConnection.SendRequest(this);
                if (searchResponse == null)
                {
                    break;
                }

                var pageResponse = (PageResultResponseControl)searchResponse.Controls[0];

                yield return searchResponse.Entries;
                if (pageResponse.Cookie.Length == 0)
                {
                    break;
                }

                Controls.OfType<PageResultRequestControl>().Single().Cookie = pageResponse.Cookie;
            }
        }
    }
}
